#pragma once
//============================================================================
// Copyright (C) 2011-2013 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================
//#include <BigListLib/BigListMgr.h>
#include <RcSktLib/RcSktConnectMgr.h>
#include <RcSysPktLib/RcSysPktAnnounce.h>

#include "RcSysPktHandler.h"
#include "RcSysSktRxEventQue.h"
#include "RcSysSktTxEventQue.h"
#include "RcSysSktBroadcast.h"

#include "RcSysRxPktAnnQue.h"
#include "RcSysRxSearchEventQue.h"

#include "RcSysInSktMgr.h"

#define UDP_ANNOUNCE_BROADCAST_INTERVAL 4

// manage all sockets for rogue connections
class RcSysSktMgr : public RcSktConnectMgr, 
					public RcSysPktHandler, 
					public RcSysSktRxEventQue, 
					public RcSysSktTxEventQue, 
					public RcSysRxPktAnnQue, 
					public RcSysRxSearchEventQue
					//public BigListMgr
{
public:
	//=== vars ===//
	RcSysPktAnnounce				m_oPktAnn;					// announce packet of this user
	OnlineId						m_oMyOnlineId;
	VxInetAddress					m_oLocalIpAddress;
	U16								m_u32UdpPort;
	bool							m_bEnableBroadcast;
	bool							m_bIsPhoneNetwork;			// if true we are on phone provider network
	bool							m_bIsOnline;


	RcSysPktAnnounce				m_oPktPing;					// announce packet of this user with type set to ping
	RcSysPktAnnounce				m_oPktPong;					// announce packet of this user with type set to pong

	RcSysInSktMgr					m_oInSktMgr;				// manager to manage incoming connections
	std::vector<VxThread *>			m_aoSendFileThrds;			// threads sending files

	//=== broadcast vars ===//
	U32								m_u32BroadcastTimeInterval; // time in seconds between broadcasts
    RcSysSktBroadcast				m_oSktBroadcast;			// socket to send and receive broadcasts
	VxThread						m_oTxEventThread;			// thread to process send events

	bool							m_bProcessEventsDirectly;	// if true process socket events with function instead of que

	//=== constructor ===//
	RcSysSktMgr();
	//=== destructor ===//
	virtual ~RcSysSktMgr(){};

	//=== methods ===//
	//! Startup
	void		sysSktMgrStartup(	VxInetAddress& oLocalIp, 
									U16 u16UdpPort, 
									bool bUdpBroadcastEnable = true );

	void		sysSktMgrShutdown( void );

	void		goOnline( void );

	void		goOffline( void );

	bool		isOnline( void ) { return m_bIsOnline; }


	virtual bool		txSystemPkt(	VxNetIdentBase *	poIdent, 
										RcSktBase *			poSkt, 
										VxPktHdr *			poPkt, 
										bool				bDisconnectAfterSend = false );

	virtual bool		txPluginPkt(	EPluginType			ePluginType, 
										VxNetIdentBase *	poIdent, 
										RcSktBase *			poSkt, 
										VxPktHdr *			poPkt, 
										bool				bDisconnectAfterSend = false );
	//=== overrides of VxSktMgr ===//

	// our receive function to receive Socket states etc
	void		HandleSktCallback(  RcSktBase * poSkt );

	//! handle udp data callbacks from sockets
	void		HandleUdpData( RcSktBase * poSkt );

	//! handle tcp data callbacks from sockets
	void		HandleTcpData( RcSktBase * poSkt );

	//=== helpers ===//
	//! return tcp/udp port
	U16			getOnlinePort( void )					{ return m_oPktAnn.m_oDirectConnectId.m_u16OnlinePort; }
	//! set tcp/udp port
	void		setOnlinePort( U16 u16Port )			{ m_oPktAnn.m_oDirectConnectId.m_u16OnlinePort = u16Port; onPktAnnUpdated(); }
	//! return tcp/udp ip address
	//VxInetAddress	getOnlineIp( void )					{ return m_oPktAnn.m_oDirectConnectId.m_oOnlineIp; }
	//! set tcp ip address
	void		setOnlineIPv4( U32 u32IpAddress )		{ m_oPktAnn.m_oDirectConnectId.m_oIPv4OnlineIp.setIp( u32IpAddress ); onPktAnnUpdated(); }
	void		setOnlineIPv6( VxInetAddress& oIp )		{ m_oPktAnn.m_oDirectConnectId.m_oIPv6OnlineIp = oIp; onPktAnnUpdated(); }

	//! return true if identity is local user
	bool		isThisMyself( RcSysPktAnnounce * poPktAnn )	{ return (poPktAnn->getSrcOnlineId() == m_oPktAnn.getSrcOnlineId());}

	//! called after m_oPktAnn has changed
	virtual void	onPktAnnUpdated( void );

	//! called if hacker offense is detected
	RCODE		HackerOffense(	VxNetIdent *	poContactIdent,			// users identity info ( may be null if not known then use ipAddress )
								U32					u32HackLevel,			// 1=severe 2=medium 3=suspicious
								VxInetAddress		u32IpAddr,				// ip address if identity not known
								const char *		pMsg, ... );			// message about the offense

	//! set announce packet with changes 
	RCODE		PktAnnounceChanged( RcSysPktAnnounce * poPktAnn );

	//! start listening
	RCODE		startListening( U16 u16Port)	{ return m_oInSktMgr.startListening( u16Port ); }
	//! stop listening
	RCODE		stopListening( void )			{ return m_oInSktMgr.stopListening(); }

	//! encrypt and send my PktAnnounce
	RCODE		SendMyPktAnnounce(	VxNetIdentBase *	poIdent, 
									RcSktBase *			poSkt, 
									EFriendState		eMyFriendshipToHim, 
									EFriendState		eHisFriendshipToMe,
									bool				bRequestAnnReply = false,
									bool				requestReverseConnection = false,
									bool				requestSTUN = false );

	//! encrypt and send my PktAnnounce to someone of whom we have no recored except from web announce
	bool		SendMyPktAnnounce(	OnlineId&			oOnlineId, 
									RcSktBase *			poSkt, 
									EFriendState		eMyFriendshipToHim, 
									EFriendState		eHisFriendshipToMe,
									bool				bRequestAnnReply = false,
									bool				requestReverseConnection = false,
									bool				requestSTUN = false );

	//! attempt direct connect to remote user
	RCODE		DirectConnectTo(	VxNetIdentBase *		poIdent,				// network identity
									RcSktBase **			ppoRetSkt,				// return pointer to socket if not null
									int						iConnectTimeout = 3000,	// how long to attempt connect
									void *					pvUserData = 0,
									bool					bUseUdpIp = false );	// pointer to user additional user defined data
	//! attempt connect to remote user's proxy ( only connects and send pkt announce )
	RCODE		RmtUserRelayConnectTo(	VxNetIdentBase *		poIdent,			// network identity
										RcSktBase **			ppoRetSkt,			// return pointer to socket if not null
										int						iConnectTimeout = 3000,	// how long to attempt connect
										void *					pvUserData = 0 );	// pointer to user additional user defined data
/*
	//! send a file using thread
	RCODE		ThreadedSendFile(		RcSktBase *		poSkt,				// connected socket
										std::string&	strFileName,		// name of file
										U64				s64StartOffs,		// offset into file to start at
										U16				u16PktSize,			// size of packets to send 
										U16				u16PktType,			// PktType to put in header 	
																			// positive value..add header of u16PktType to each chunk sent
																			//  -1 = use no headers..send file in chunks of u32PktSize in length
																			//	-2 = file is file of packets..add u32PktSize to each pkt type
										U32				u32Instance,			// instance value if has header
										BOOL			bDeleteFile, 			// if true delete file after sent
										BOOL			bDisconnect,			// if true close connection after file is sent
										BOOL			bSendEncrypted,			// if true send encrypted
										U64				u64UserData,
										RC_SEND_FILE_STATUS_CALLBACK	fnStatusCallback );

	//! send file of packets
	RCODE		ThreadSendFileOfPkts(	std::string&	strFileName,		//name of file
										U16				u16PktSize,			//size of packets to send
										BOOL			bDeleteAfterUse,	//if true delete file after sent
										BOOL			bCloseAfterSend,	//if true close connection after file is sent
										BOOL			bEncrypt );			//if true encrypt */

	//! process events in rxed pkt ann que.. return true if any packets processed
	BOOL ProcessRxPktAnnQue( void );
	//! process events in rxed search event que.. return true if any packets processed
	BOOL ProcessRxSearchEventQue( void );
	//! process events in tx que
	void ProcessTxEventQue( void );
	//! process events in rx que.. return true if any packets processed
	BOOL ProcessRxEventQue( void );

	// override to process skt events as they occur instead of from que
	virtual RCODE ProcessSktEvent(  RcSktBase * poSkt, RcSysPktHdr * poPkt, ESktCallbackReason eCallbackReason ){return 0;}

	//! this is called if incoming http connection
	virtual long HandleHttpConnection	( RcSktBase * poSktBase );
};

//! must call this from any thread that might access gui before makeing changes
//! NOTE: cannot call this from gui thread because causes problems
//! NOTE: if called twice before calling UnlockGuiMutex causes deadlock
void LockGuiMutex( void );
//! must call this after gui access 
void UnlockGuiMutex( void );
